package net.goutalk.glcs.module.form.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.toolkit.MPJWrappers;
import net.goutalk.glcs.common.annotation.GlcsLog;
import net.goutalk.glcs.common.constant.GlobalConstant;
import net.goutalk.glcs.common.enums.YesOrNoEnum;
import net.goutalk.glcs.common.model.generator.FormConfig;
import net.goutalk.glcs.common.model.result.R;
import net.goutalk.glcs.common.page.ConventPage;
import net.goutalk.glcs.common.page.PageOutput;
import net.goutalk.glcs.common.utils.VoToColumnUtil;
import net.goutalk.glcs.module.form.dto.*;
import net.goutalk.glcs.module.form.entity.FormHistory;
import net.goutalk.glcs.module.form.entity.FormRelease;
import net.goutalk.glcs.module.form.entity.FormTemplate;
import net.goutalk.glcs.module.form.service.IFormHistoryService;
import net.goutalk.glcs.module.form.service.IFormReleaseService;
import net.goutalk.glcs.module.form.service.IFormTemplateService;
import net.goutalk.glcs.module.form.vo.FormTemplateListVo;
import net.goutalk.glcs.module.form.vo.FormTemplatePageVo;
import net.goutalk.glcs.module.form.vo.FormTemplateVo;
import net.goutalk.glcs.module.generator.dto.DataFirstPreviewDto;
import net.goutalk.glcs.module.generator.entity.ListConfig;
import net.goutalk.glcs.module.generator.entity.MenuConfig;
import net.goutalk.glcs.module.generator.entity.TableConfig;
import net.goutalk.glcs.module.generator.service.IGeneratorService;
import net.goutalk.glcs.module.organization.entity.User;
import net.goutalk.glcs.module.system.entity.DictionaryDetail;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 表单设计模板  前端控制器
 * </p>
 *
 * @author tanyujie
 * @since 2022-05-09
 */
@RestController
@RequestMapping(GlobalConstant.FORM_MODULE_PREFIX + "/template")
@Api(value = GlobalConstant.FORM_MODULE_PREFIX + "/template", tags = "自定义表单-代码生成器 模板设计")
@AllArgsConstructor
public class FormTemplateController {

    private final IFormTemplateService formTemplateService;

    private final IFormHistoryService formHistoryService;

    private final IFormReleaseService formReleaseService;

    private final IGeneratorService generatorService;



    @GetMapping(value = "/list")
    @ApiOperation(value = "表单设计模板(不分页)")
    @GlcsLog(value = "表单设计模板")
    public R list(@Valid FormTemplateListDto dto) {
        List<FormTemplate> list = formTemplateService.list(Wrappers.lambdaQuery(FormTemplate.class)
                .eq(FormTemplate::getFormType, dto.getType())
                .eq(dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                .orderByDesc(FormTemplate::getCreateDate)
                .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplateListVo.class).contains(x.getProperty())));

        List<FormTemplateListVo> formTemplateListVos = BeanUtil.copyToList(list, FormTemplateListVo.class);
        return R.ok(formTemplateListVos);
    }

    @GetMapping(value = "/page")
    @ApiOperation(value = "表单设计模板(分页),过滤未启用数据")
    @GlcsLog(value = "表单设计模板")
    public R page(@Valid FormTemplatePageDto dto) {

        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .eq(FormTemplate::getEnabledMark, YesOrNoEnum.YES.getCode())
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/enabled-page")
    @ApiOperation(value = "表单设计模板(分页)，不过滤未启用数据")
    @GlcsLog(value = "表单设计模板")
    public R pageEnabled(@Valid FormTemplatePageDto dto) {

        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "表单设计模板详情")
    @GlcsLog(value = "表单设计模板详情")
    public R info(@RequestParam Long id) {
        FormTemplate template = formTemplateService.getById(id);
        if (template == null) {
            return R.error("找不到此数据！");
        }
        return R.ok(BeanUtil.toBean(template, FormTemplateVo.class));
    }

    @GetMapping(value = "/info/multi")
    @ApiOperation(value = "表单设计模板详情(批量查询)")
    @GlcsLog(value = "表单设计模板详情(批量查询)")
    public R multiInfo(@RequestParam String id) {
        List<FormTemplate> formTemplates = formTemplateService.listByIds(Arrays.asList(id.split(StringPool.COMMA)));
        List<FormTemplateVo> formTemplateVos = BeanUtil.copyToList(formTemplates, FormTemplateVo.class);
        return R.ok(formTemplateVos);
    }

    @PutMapping("/status")
    @ApiOperation(value = "修改表单状态")
    @GlcsLog(value = "修改表单状态")
    public R updateEnabled(@Valid @RequestBody UpdateTemplateStatusDto dto) {
        //根据id修改表单enabledMark
        return R.ok(formTemplateService.update(Wrappers.<FormTemplate>update().lambda().set(FormTemplate::getEnabledMark, dto.getEnabledMark()).eq(FormTemplate::getId, dto.getId())));
    }

    @PostMapping(value = "/data-first")
    @ApiOperation(value = "数据优先 新增")
    @GlcsLog(value = "数据优先新增")
    public R addDataFirst(@Valid @RequestBody AddFormDataFirstDto dto) {
        return R.ok(formTemplateService.addDataFirst(dto));
    }

    @PostMapping(value = "/code-first")
    @ApiOperation(value = "界面优先 或者  简易模板 新增")
    @GlcsLog(value = "界面优先 或者 简易模板新增")
    public R addCodeFirst(@Valid @RequestBody AddFormCodeFirstDto dto) {
        return R.ok(formTemplateService.addCodeFirst(dto));
    }

    @PutMapping(value = "/data-first")
    @ApiOperation(value = "修改数据优先")
    @GlcsLog(value = "修改数据优先")
    public R updateDataFirst(@Valid @RequestBody UpdateFormDataFirstDto dto) {
        return R.ok(formTemplateService.updateDataFirst(dto));
    }


    @PutMapping(value = "/code-first")
    @ApiOperation(value = "修改界面优先")
    @GlcsLog(value = "修改界面优先")
    public R updateCodeFirst(@Valid @RequestBody UpdateFormCodeFirstDto dto){
        return R.ok(formTemplateService.updateCodeFirst(dto));
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    public R delete(@Valid @RequestBody List<Long> ids) {
        formHistoryService.remove(Wrappers.lambdaQuery(FormHistory.class).in(FormHistory::getFormId, ids));
        return R.ok(formTemplateService.removeBatchByIds(ids));
    }

    @PostMapping(value = "/test-code")
    @ApiOperation(value = "表单测试代码生成器")
    @GlcsLog(value = "测试表单预览代码生成器")
    public R test(@Valid @RequestBody DateTestDto dto){
        FormRelease formRelease = formReleaseService.getById(dto.getFormReleaseId());
        FormTemplate formTemplate = formTemplateService.getById(dto.getFormTemplateId());
        JSONObject configJson = JSON.parseObject(formRelease.getConfigJson());
        JSONObject formJson = JSON.parseObject(formTemplate.getFormJson());
        dto.setDatabaseId(formJson.get("databaseId").toString());
        dto.setTableConfigs(JSONObject.parseArray(formJson.getString("tableConfigs"),TableConfig.class));
        dto.setFormJson(JSON.parseObject(formJson.getString("formJson"), FormConfig.class));
        dto.setListConfig(JSON.parseObject(configJson.getString("listConfig"), ListConfig.class));
        dto.setMenuConfig(JSON.parseObject(configJson.getString("menuConfig"), MenuConfig.class));
        dto.setOutputConfig(dto.getOutputConfig());
        return R.ok(generatorService.getPreviewCodes(BeanUtil.toBean(dto, DataFirstPreviewDto.class)));
    }

}

